+Wed Jan 27 20:06:06 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+ Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/gdk.h gdk/gdkdnd.c: Change signatures for
+ gdk_drag_begin() and gdk_drag_motion() so that the set
+ of possible actions is passed on each motion, not just at
+ the beginning of the drag. We do this so that
+ we can restrict the set of possible drag events
+ when the user presses a modifier key during a
+ drag.
+
+ * gdk/gdkdnd.c: Send a motif Operation-changed
+ message when the set of possible actions change,
+ as well as when the suggested action change.
+
+ * gdk/gdkdnd.c: Change the XdndActionList whenever
+ the set of actions change.
+
+ * gdk/gdkdnd.c: Add a filter to catch changes to
+ the XdndActionList property for the source widget.
+
+ * gtk/gtkdnd.c: Change the set of possible actions
+ when the user presses Control, Shift, or Control-Shift,
+ to only include the corresponding action.
+
+ * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+ Disconnect button signals before we possibly
+ free info structure.
+
Wed Jan 27 18:40:50 1999 Owen Taylor <otaylor@redhat.com>
* gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
+Wed Jan 27 20:06:06 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+ Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/gdk.h gdk/gdkdnd.c: Change signatures for
+ gdk_drag_begin() and gdk_drag_motion() so that the set
+ of possible actions is passed on each motion, not just at
+ the beginning of the drag. We do this so that
+ we can restrict the set of possible drag events
+ when the user presses a modifier key during a
+ drag.
+
+ * gdk/gdkdnd.c: Send a motif Operation-changed
+ message when the set of possible actions change,
+ as well as when the suggested action change.
+
+ * gdk/gdkdnd.c: Change the XdndActionList whenever
+ the set of actions change.
+
+ * gdk/gdkdnd.c: Add a filter to catch changes to
+ the XdndActionList property for the source widget.
+
+ * gtk/gtkdnd.c: Change the set of possible actions
+ when the user presses Control, Shift, or Control-Shift,
+ to only include the corresponding action.
+
+ * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+ Disconnect button signals before we possibly
+ free info structure.
+
Wed Jan 27 18:40:50 1999 Owen Taylor <otaylor@redhat.com>
* gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
+Wed Jan 27 20:06:06 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+ Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/gdk.h gdk/gdkdnd.c: Change signatures for
+ gdk_drag_begin() and gdk_drag_motion() so that the set
+ of possible actions is passed on each motion, not just at
+ the beginning of the drag. We do this so that
+ we can restrict the set of possible drag events
+ when the user presses a modifier key during a
+ drag.
+
+ * gdk/gdkdnd.c: Send a motif Operation-changed
+ message when the set of possible actions change,
+ as well as when the suggested action change.
+
+ * gdk/gdkdnd.c: Change the XdndActionList whenever
+ the set of actions change.
+
+ * gdk/gdkdnd.c: Add a filter to catch changes to
+ the XdndActionList property for the source widget.
+
+ * gtk/gtkdnd.c: Change the set of possible actions
+ when the user presses Control, Shift, or Control-Shift,
+ to only include the corresponding action.
+
+ * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+ Disconnect button signals before we possibly
+ free info structure.
+
Wed Jan 27 18:40:50 1999 Owen Taylor <otaylor@redhat.com>
* gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
+Wed Jan 27 20:06:06 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+ Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/gdk.h gdk/gdkdnd.c: Change signatures for
+ gdk_drag_begin() and gdk_drag_motion() so that the set
+ of possible actions is passed on each motion, not just at
+ the beginning of the drag. We do this so that
+ we can restrict the set of possible drag events
+ when the user presses a modifier key during a
+ drag.
+
+ * gdk/gdkdnd.c: Send a motif Operation-changed
+ message when the set of possible actions change,
+ as well as when the suggested action change.
+
+ * gdk/gdkdnd.c: Change the XdndActionList whenever
+ the set of actions change.
+
+ * gdk/gdkdnd.c: Add a filter to catch changes to
+ the XdndActionList property for the source widget.
+
+ * gtk/gtkdnd.c: Change the set of possible actions
+ when the user presses Control, Shift, or Control-Shift,
+ to only include the corresponding action.
+
+ * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+ Disconnect button signals before we possibly
+ free info structure.
+
Wed Jan 27 18:40:50 1999 Owen Taylor <otaylor@redhat.com>
* gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
+Wed Jan 27 20:06:06 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+ Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/gdk.h gdk/gdkdnd.c: Change signatures for
+ gdk_drag_begin() and gdk_drag_motion() so that the set
+ of possible actions is passed on each motion, not just at
+ the beginning of the drag. We do this so that
+ we can restrict the set of possible drag events
+ when the user presses a modifier key during a
+ drag.
+
+ * gdk/gdkdnd.c: Send a motif Operation-changed
+ message when the set of possible actions change,
+ as well as when the suggested action change.
+
+ * gdk/gdkdnd.c: Change the XdndActionList whenever
+ the set of actions change.
+
+ * gdk/gdkdnd.c: Add a filter to catch changes to
+ the XdndActionList property for the source widget.
+
+ * gtk/gtkdnd.c: Change the set of possible actions
+ when the user presses Control, Shift, or Control-Shift,
+ to only include the corresponding action.
+
+ * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+ Disconnect button signals before we possibly
+ free info structure.
+
Wed Jan 27 18:40:50 1999 Owen Taylor <otaylor@redhat.com>
* gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
+Wed Jan 27 20:06:06 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+ Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/gdk.h gdk/gdkdnd.c: Change signatures for
+ gdk_drag_begin() and gdk_drag_motion() so that the set
+ of possible actions is passed on each motion, not just at
+ the beginning of the drag. We do this so that
+ we can restrict the set of possible drag events
+ when the user presses a modifier key during a
+ drag.
+
+ * gdk/gdkdnd.c: Send a motif Operation-changed
+ message when the set of possible actions change,
+ as well as when the suggested action change.
+
+ * gdk/gdkdnd.c: Change the XdndActionList whenever
+ the set of actions change.
+
+ * gdk/gdkdnd.c: Add a filter to catch changes to
+ the XdndActionList property for the source widget.
+
+ * gtk/gtkdnd.c: Change the set of possible actions
+ when the user presses Control, Shift, or Control-Shift,
+ to only include the corresponding action.
+
+ * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+ Disconnect button signals before we possibly
+ free info structure.
+
Wed Jan 27 18:40:50 1999 Owen Taylor <otaylor@redhat.com>
* gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
+Wed Jan 27 20:06:06 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gtk/gtklayout.c (gtk_layout_adjustment_changed):
+ Removed some g_print()'s
+
+Wed Jan 27 18:57:57 1999 Owen Taylor <otaylor@redhat.com>
+
+ * gdk/gdk.h gdk/gdkdnd.c: Change signatures for
+ gdk_drag_begin() and gdk_drag_motion() so that the set
+ of possible actions is passed on each motion, not just at
+ the beginning of the drag. We do this so that
+ we can restrict the set of possible drag events
+ when the user presses a modifier key during a
+ drag.
+
+ * gdk/gdkdnd.c: Send a motif Operation-changed
+ message when the set of possible actions change,
+ as well as when the suggested action change.
+
+ * gdk/gdkdnd.c: Change the XdndActionList whenever
+ the set of actions change.
+
+ * gdk/gdkdnd.c: Add a filter to catch changes to
+ the XdndActionList property for the source widget.
+
+ * gtk/gtkdnd.c: Change the set of possible actions
+ when the user presses Control, Shift, or Control-Shift,
+ to only include the corresponding action.
+
+ * gtk/gtkdnd.c (gtk_drag_button_release_cb):
+ Disconnect button signals before we possibly
+ free info structure.
+
Wed Jan 27 18:40:50 1999 Owen Taylor <otaylor@redhat.com>
* gtk/gtkmain.c (gtk_main_do_event): Hack scrollwheel
/* Source side */
GdkDragContext * gdk_drag_begin (GdkWindow *window,
- GList *targets,
- GdkDragAction actions);
+ GList *targets);
guint32 gdk_drag_get_protocol (guint32 xid,
GdkDragProtocol *protocol);
void gdk_drag_find_window (GdkDragContext *context,
GdkDragProtocol protocol,
gint x_root,
gint y_root,
- GdkDragAction action,
+ GdkDragAction suggested_action,
+ GdkDragAction possible_actions,
guint32 time);
void gdk_drag_drop (GdkDragContext *context,
guint32 time);
guint16 last_x; /* Coordinates from last event */
guint16 last_y;
- GdkDragAction old_action; /* The last action we sent to the source */
+ GdkDragAction old_action; /* The last action we sent to the source */
+ GdkDragAction old_actions; /* The last actions we sent to the source */
+ GdkDragAction xdnd_actions; /* What is currently set in XdndActionList */
Window dest_xid;
guint xdnd_targets_set : 1; /* Whether we've already set XdndTypeList */
- guint xdnd_actions_set : 1; /* Whether we've already set XdndActionsList */
+ guint xdnd_actions_set : 1; /* Whether we've already set XdndActionList */
guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */
guint motif_targets_set : 1; /* Whether we've already set motif initiator info */
guint drag_status : 4; /* current status of drag */
GdkEvent *event,
gpointer data);
+static void xdnd_manage_source_filter (GdkDragContext *context,
+ GdkWindow *window,
+ gboolean add_filter);
+
/* Drag Contexts */
static GList *contexts;
g_list_free (context->targets);
if (context->source_window)
- gdk_window_unref (context->source_window);
+ {
+ if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
+ !context->is_source)
+ xdnd_manage_source_filter (context, context->source_window, FALSE);
+
+ gdk_window_unref (context->source_window);
+ }
if (context->dest_window)
gdk_window_unref (context->dest_window);
MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
MOTIF_XCLIENT_LONG (&xev, 1) = time;
- if (context->suggested_action != private->old_action)
+ if ((context->suggested_action != private->old_action) ||
+ (context->actions != private->old_actions))
{
MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
- private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
+ /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
retval = TRUE;
}
else
if (context)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
- if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+ if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
+ (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
private->drag_status = GDK_DRAG_STATUS_DRAG;
event->dnd.type = GDK_DRAG_STATUS;
if (!xdnd_actions_initialized)
xdnd_initialize_actions();
-
+
actions = context->actions;
n_atoms = 0;
for (i=0; i<xdnd_n_actions; i++)
(guchar *)atomlist, n_atoms);
private->xdnd_actions_set = 1;
+ private->xdnd_actions = context->actions;
}
static void
}
}
- if (!private->xdnd_actions_set)
- xdnd_set_actions (context);
-
if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
FALSE, 0, &xev))
{
/* Target side */
+static void
+xdnd_read_actions (GdkDragContext *context)
+{
+ Atom type;
+ int format;
+ gulong nitems, after;
+ Atom *data;
+
+ gint i;
+
+ gint old_warnings = gdk_error_warnings;
+
+ gdk_error_code = 0;
+ gdk_error_warnings = 0;
+
+ /* Get the XdndActionList, if set */
+
+ XGetWindowProperty (GDK_WINDOW_XDISPLAY (context->source_window),
+ GDK_WINDOW_XWINDOW (context->source_window),
+ gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
+ False, XA_ATOM, &type, &format, &nitems,
+ &after, (guchar **)&data);
+
+ if (!gdk_error_code && (format == 32) && (type == XA_ATOM))
+ {
+ context->actions = 0;
+
+ for (i=0; i<nitems; i++)
+ context->actions |= xdnd_action_from_atom (data[i]);
+
+ ((GdkDragContextPrivate *)context)->xdnd_have_actions = TRUE;
+
+#ifdef G_ENABLE_DEBUG
+ if (gdk_debug_flags & GDK_DEBUG_DND)
+ {
+ GString *action_str = g_string_new (NULL);
+ if (context->actions & GDK_ACTION_MOVE)
+ g_string_append(action_str, "MOVE ");
+ if (context->actions & GDK_ACTION_COPY)
+ g_string_append(action_str, "COPY ");
+ if (context->actions & GDK_ACTION_LINK)
+ g_string_append(action_str, "LINK ");
+ if (context->actions & GDK_ACTION_ASK)
+ g_string_append(action_str, "ASK ");
+
+ g_message("Xdnd actions = %s", action_str->str);
+ g_string_free (action_str, TRUE);
+ }
+#endif /* G_ENABLE_DEBUG */
+
+ XFree(data);
+ }
+
+ gdk_error_warnings = old_warnings;
+ gdk_error_code = 0;
+}
+
+/* We have to make sure that the XdndActionList we keep internally
+ * is up to date with the XdndActionList on the source window
+ * because we get no notification, because Xdnd wasn't meant
+ * to continually send actions. So we select on PropertyChangeMask
+ * and add this filter.
+ */
+static GdkFilterReturn
+xdnd_source_window_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer cb_data)
+{
+ XEvent *xevent = (XEvent *)xev;
+ GdkDragContext *context = cb_data;
+
+ if ((xevent->xany.type == PropertyNotify) &&
+ (xevent->xproperty.atom == gdk_atom_intern ("XdndActionList", FALSE)))
+ {
+ xdnd_read_actions (context);
+
+ return GDK_FILTER_REMOVE;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+xdnd_manage_source_filter (GdkDragContext *context,
+ GdkWindow *window,
+ gboolean add_filter)
+{
+ gint old_warnings = 0; /* quiet gcc */
+ GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+ gboolean is_foreign = (private->window_type == GDK_WINDOW_FOREIGN);
+
+ if (is_foreign)
+ {
+ old_warnings = gdk_error_warnings;
+ gdk_error_warnings = 0;
+ }
+
+ if (!private->destroyed)
+ {
+ if (add_filter)
+ {
+ gdk_window_set_events (window,
+ gdk_window_get_events (window) |
+ GDK_PROPERTY_CHANGE_MASK);
+ gdk_window_add_filter (window, xdnd_source_window_filter, context);
+
+ }
+ else
+ {
+ gdk_window_remove_filter (window,
+ xdnd_source_window_filter,
+ context);
+ /* Should we remove the GDK_PROPERTY_NOTIFY mask?
+ * but we might want it for other reasons. (Like
+ * INCR selection transactions).
+ */
+ }
+ }
+
+ if (is_foreign)
+ {
+ gdk_flush();
+ gdk_error_warnings = old_warnings;
+ }
+}
+
static GdkFilterReturn
xdnd_enter_filter (GdkXEvent *xev,
GdkEvent *event,
GUINT_TO_POINTER (xevent->xclient.data.l[2+i]));
}
- /* Get the XdndActionList, if set */
-
- XGetWindowProperty (GDK_WINDOW_XDISPLAY (event->any.window),
- source_window,
- gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
- False, XA_ATOM, &type, &format, &nitems,
- &after, (guchar **)&data);
-
- if ((format == 32) && (type == XA_ATOM))
- {
- new_context->actions = 0;
-
- for (i=0; i<nitems; i++)
- new_context->actions |= xdnd_action_from_atom (data[i]);
-
- ((GdkDragContextPrivate *)new_context)->xdnd_have_actions = TRUE;
-
-#ifdef G_ENABLE_DEBUG
- if (gdk_debug_flags & GDK_DEBUG_DND)
- {
- GString *action_str = g_string_new (NULL);
- if (new_context->actions & GDK_ACTION_MOVE)
- g_string_append(action_str, "MOVE ");
- if (new_context->actions & GDK_ACTION_COPY)
- g_string_append(action_str, "COPY ");
- if (new_context->actions & GDK_ACTION_LINK)
- g_string_append(action_str, "LINK ");
- if (new_context->actions & GDK_ACTION_ASK)
- g_string_append(action_str, "ASK ");
-
- g_message("\tactions = %s", action_str->str);
- g_string_free (action_str, TRUE);
- }
-#endif /* G_ENABLE_DEBUG */
-
- XFree(data);
- }
-
#ifdef G_ENABLE_DEBUG
if (gdk_debug_flags & GDK_DEBUG_DND)
print_target_list (new_context->targets);
#endif /* G_ENABLE_DEBUG */
+ xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
+ xdnd_read_actions (new_context);
+
event->dnd.type = GDK_DRAG_ENTER;
event->dnd.context = new_context;
gdk_drag_context_ref (new_context);
GdkDragContext *
gdk_drag_begin (GdkWindow *window,
- GList *targets,
- GdkDragAction actions)
+ GList *targets)
{
GList *tmp_list;
GdkDragContext *new_context;
tmp_list = tmp_list->prev;
}
- new_context->actions = actions;
+ new_context->actions = 0;
return new_context;
}
GdkDragProtocol protocol,
gint x_root,
gint y_root,
- GdkDragAction action,
+ GdkDragAction suggested_action,
+ GdkDragAction possible_actions,
guint32 time)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
g_return_val_if_fail (context != NULL, FALSE);
+ /* When we have a Xdnd target, make sure our XdndActionList
+ * matches the current actions;
+ */
+ private->old_actions = context->actions;
+ context->actions = possible_actions;
+
+ if ((protocol == GDK_DRAG_PROTO_XDND) &&
+ (!private->xdnd_actions_set ||
+ private->xdnd_actions != possible_actions))
+ xdnd_set_actions (context);
+
if (context->dest_window != dest_window)
{
GdkEvent temp_event;
case GDK_DRAG_PROTO_NONE:
break;
}
- private->old_action = action;
- context->suggested_action = action;
+ private->old_action = suggested_action;
+ context->suggested_action = suggested_action;
+ private->old_actions = possible_actions;
}
else
{
else
{
private->old_action = context->suggested_action;
- context->suggested_action = action;
+ context->suggested_action = suggested_action;
}
/* Send a drag-motion event */
switch (context->protocol)
{
case GDK_DRAG_PROTO_MOTIF:
- motif_send_motion (context, x_root, y_root, action, time);
+ motif_send_motion (context, x_root, y_root, suggested_action, time);
break;
case GDK_DRAG_PROTO_XDND:
- xdnd_send_motion (context, x_root, y_root, action, time);
+ xdnd_send_motion (context, x_root, y_root, suggested_action, time);
break;
case GDK_DRAG_PROTO_ROOTWIN:
guint16 last_x; /* Coordinates from last event */
guint16 last_y;
- GdkDragAction old_action; /* The last action we sent to the source */
+ GdkDragAction old_action; /* The last action we sent to the source */
+ GdkDragAction old_actions; /* The last actions we sent to the source */
+ GdkDragAction xdnd_actions; /* What is currently set in XdndActionList */
Window dest_xid;
guint xdnd_targets_set : 1; /* Whether we've already set XdndTypeList */
- guint xdnd_actions_set : 1; /* Whether we've already set XdndActionsList */
+ guint xdnd_actions_set : 1; /* Whether we've already set XdndActionList */
guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */
guint motif_targets_set : 1; /* Whether we've already set motif initiator info */
guint drag_status : 4; /* current status of drag */
GdkEvent *event,
gpointer data);
+static void xdnd_manage_source_filter (GdkDragContext *context,
+ GdkWindow *window,
+ gboolean add_filter);
+
/* Drag Contexts */
static GList *contexts;
g_list_free (context->targets);
if (context->source_window)
- gdk_window_unref (context->source_window);
+ {
+ if ((context->protocol == GDK_DRAG_PROTO_XDND) &&
+ !context->is_source)
+ xdnd_manage_source_filter (context, context->source_window, FALSE);
+
+ gdk_window_unref (context->source_window);
+ }
if (context->dest_window)
gdk_window_unref (context->dest_window);
MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context);
MOTIF_XCLIENT_LONG (&xev, 1) = time;
- if (context->suggested_action != private->old_action)
+ if ((context->suggested_action != private->old_action) ||
+ (context->actions != private->old_actions))
{
MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED;
- private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT;
+ /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */
retval = TRUE;
}
else
if (context)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
- if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT)
+ if ((private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) ||
+ (private->drag_status == GDK_DRAG_STATUS_ACTION_WAIT))
private->drag_status = GDK_DRAG_STATUS_DRAG;
event->dnd.type = GDK_DRAG_STATUS;
if (!xdnd_actions_initialized)
xdnd_initialize_actions();
-
+
actions = context->actions;
n_atoms = 0;
for (i=0; i<xdnd_n_actions; i++)
(guchar *)atomlist, n_atoms);
private->xdnd_actions_set = 1;
+ private->xdnd_actions = context->actions;
}
static void
}
}
- if (!private->xdnd_actions_set)
- xdnd_set_actions (context);
-
if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window),
FALSE, 0, &xev))
{
/* Target side */
+static void
+xdnd_read_actions (GdkDragContext *context)
+{
+ Atom type;
+ int format;
+ gulong nitems, after;
+ Atom *data;
+
+ gint i;
+
+ gint old_warnings = gdk_error_warnings;
+
+ gdk_error_code = 0;
+ gdk_error_warnings = 0;
+
+ /* Get the XdndActionList, if set */
+
+ XGetWindowProperty (GDK_WINDOW_XDISPLAY (context->source_window),
+ GDK_WINDOW_XWINDOW (context->source_window),
+ gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
+ False, XA_ATOM, &type, &format, &nitems,
+ &after, (guchar **)&data);
+
+ if (!gdk_error_code && (format == 32) && (type == XA_ATOM))
+ {
+ context->actions = 0;
+
+ for (i=0; i<nitems; i++)
+ context->actions |= xdnd_action_from_atom (data[i]);
+
+ ((GdkDragContextPrivate *)context)->xdnd_have_actions = TRUE;
+
+#ifdef G_ENABLE_DEBUG
+ if (gdk_debug_flags & GDK_DEBUG_DND)
+ {
+ GString *action_str = g_string_new (NULL);
+ if (context->actions & GDK_ACTION_MOVE)
+ g_string_append(action_str, "MOVE ");
+ if (context->actions & GDK_ACTION_COPY)
+ g_string_append(action_str, "COPY ");
+ if (context->actions & GDK_ACTION_LINK)
+ g_string_append(action_str, "LINK ");
+ if (context->actions & GDK_ACTION_ASK)
+ g_string_append(action_str, "ASK ");
+
+ g_message("Xdnd actions = %s", action_str->str);
+ g_string_free (action_str, TRUE);
+ }
+#endif /* G_ENABLE_DEBUG */
+
+ XFree(data);
+ }
+
+ gdk_error_warnings = old_warnings;
+ gdk_error_code = 0;
+}
+
+/* We have to make sure that the XdndActionList we keep internally
+ * is up to date with the XdndActionList on the source window
+ * because we get no notification, because Xdnd wasn't meant
+ * to continually send actions. So we select on PropertyChangeMask
+ * and add this filter.
+ */
+static GdkFilterReturn
+xdnd_source_window_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer cb_data)
+{
+ XEvent *xevent = (XEvent *)xev;
+ GdkDragContext *context = cb_data;
+
+ if ((xevent->xany.type == PropertyNotify) &&
+ (xevent->xproperty.atom == gdk_atom_intern ("XdndActionList", FALSE)))
+ {
+ xdnd_read_actions (context);
+
+ return GDK_FILTER_REMOVE;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+xdnd_manage_source_filter (GdkDragContext *context,
+ GdkWindow *window,
+ gboolean add_filter)
+{
+ gint old_warnings = 0; /* quiet gcc */
+ GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+ gboolean is_foreign = (private->window_type == GDK_WINDOW_FOREIGN);
+
+ if (is_foreign)
+ {
+ old_warnings = gdk_error_warnings;
+ gdk_error_warnings = 0;
+ }
+
+ if (!private->destroyed)
+ {
+ if (add_filter)
+ {
+ gdk_window_set_events (window,
+ gdk_window_get_events (window) |
+ GDK_PROPERTY_CHANGE_MASK);
+ gdk_window_add_filter (window, xdnd_source_window_filter, context);
+
+ }
+ else
+ {
+ gdk_window_remove_filter (window,
+ xdnd_source_window_filter,
+ context);
+ /* Should we remove the GDK_PROPERTY_NOTIFY mask?
+ * but we might want it for other reasons. (Like
+ * INCR selection transactions).
+ */
+ }
+ }
+
+ if (is_foreign)
+ {
+ gdk_flush();
+ gdk_error_warnings = old_warnings;
+ }
+}
+
static GdkFilterReturn
xdnd_enter_filter (GdkXEvent *xev,
GdkEvent *event,
GUINT_TO_POINTER (xevent->xclient.data.l[2+i]));
}
- /* Get the XdndActionList, if set */
-
- XGetWindowProperty (GDK_WINDOW_XDISPLAY (event->any.window),
- source_window,
- gdk_atom_intern ("XdndActionList", FALSE), 0, 65536,
- False, XA_ATOM, &type, &format, &nitems,
- &after, (guchar **)&data);
-
- if ((format == 32) && (type == XA_ATOM))
- {
- new_context->actions = 0;
-
- for (i=0; i<nitems; i++)
- new_context->actions |= xdnd_action_from_atom (data[i]);
-
- ((GdkDragContextPrivate *)new_context)->xdnd_have_actions = TRUE;
-
-#ifdef G_ENABLE_DEBUG
- if (gdk_debug_flags & GDK_DEBUG_DND)
- {
- GString *action_str = g_string_new (NULL);
- if (new_context->actions & GDK_ACTION_MOVE)
- g_string_append(action_str, "MOVE ");
- if (new_context->actions & GDK_ACTION_COPY)
- g_string_append(action_str, "COPY ");
- if (new_context->actions & GDK_ACTION_LINK)
- g_string_append(action_str, "LINK ");
- if (new_context->actions & GDK_ACTION_ASK)
- g_string_append(action_str, "ASK ");
-
- g_message("\tactions = %s", action_str->str);
- g_string_free (action_str, TRUE);
- }
-#endif /* G_ENABLE_DEBUG */
-
- XFree(data);
- }
-
#ifdef G_ENABLE_DEBUG
if (gdk_debug_flags & GDK_DEBUG_DND)
print_target_list (new_context->targets);
#endif /* G_ENABLE_DEBUG */
+ xdnd_manage_source_filter (new_context, new_context->source_window, TRUE);
+ xdnd_read_actions (new_context);
+
event->dnd.type = GDK_DRAG_ENTER;
event->dnd.context = new_context;
gdk_drag_context_ref (new_context);
GdkDragContext *
gdk_drag_begin (GdkWindow *window,
- GList *targets,
- GdkDragAction actions)
+ GList *targets)
{
GList *tmp_list;
GdkDragContext *new_context;
tmp_list = tmp_list->prev;
}
- new_context->actions = actions;
+ new_context->actions = 0;
return new_context;
}
GdkDragProtocol protocol,
gint x_root,
gint y_root,
- GdkDragAction action,
+ GdkDragAction suggested_action,
+ GdkDragAction possible_actions,
guint32 time)
{
GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
g_return_val_if_fail (context != NULL, FALSE);
+ /* When we have a Xdnd target, make sure our XdndActionList
+ * matches the current actions;
+ */
+ private->old_actions = context->actions;
+ context->actions = possible_actions;
+
+ if ((protocol == GDK_DRAG_PROTO_XDND) &&
+ (!private->xdnd_actions_set ||
+ private->xdnd_actions != possible_actions))
+ xdnd_set_actions (context);
+
if (context->dest_window != dest_window)
{
GdkEvent temp_event;
case GDK_DRAG_PROTO_NONE:
break;
}
- private->old_action = action;
- context->suggested_action = action;
+ private->old_action = suggested_action;
+ context->suggested_action = suggested_action;
+ private->old_actions = possible_actions;
}
else
{
else
{
private->old_action = context->suggested_action;
- context->suggested_action = action;
+ context->suggested_action = suggested_action;
}
/* Send a drag-motion event */
switch (context->protocol)
{
case GDK_DRAG_PROTO_MOTIF:
- motif_send_motion (context, x_root, y_root, action, time);
+ motif_send_motion (context, x_root, y_root, suggested_action, time);
break;
case GDK_DRAG_PROTO_XDND:
- xdnd_send_motion (context, x_root, y_root, action, time);
+ xdnd_send_motion (context, x_root, y_root, suggested_action, time);
break;
case GDK_DRAG_PROTO_ROOTWIN:
struct _GtkDragSourceInfo {
GtkWidget *widget;
GtkTargetList *target_list; /* Targets for drag data */
+ GdkDragAction possible_actions; /* Actions allowed by source */
GdkDragContext *context; /* drag context */
GtkWidget *icon_window; /* Window for drag */
GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
static gint default_icon_hot_y;
/* Forward declarations */
-static GdkDragAction gtk_drag_get_event_action (GdkEvent *event,
- gint button,
- GdkDragAction actions);
+static void gtk_drag_get_event_actions (GdkEvent *event,
+ gint button,
+ GdkDragAction actions,
+ GdkDragAction *suggested_action,
+ GdkDragAction *possible_actions);
static GdkCursor * gtk_drag_get_cursor (GdkDragAction action);
static GtkWidget *gtk_drag_get_ipc_widget (void);
static void gtk_drag_release_ipc_widget (GtkWidget *widget);
drag_widgets = g_slist_prepend (drag_widgets, widget);
}
-static GdkDragAction
-gtk_drag_get_event_action (GdkEvent *event, gint button, GdkDragAction actions)
+static void
+gtk_drag_get_event_actions (GdkEvent *event,
+ gint button,
+ GdkDragAction actions,
+ GdkDragAction *suggested_action,
+ GdkDragAction *possible_actions)
{
+ *suggested_action = 0;
+ *possible_actions = 0;
+
if (event)
{
GdkModifierType state = 0;
}
if (((button == 2) || (button == 3)) && (actions & GDK_ACTION_ASK))
- return GDK_ACTION_ASK;
-
- if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
+ {
+ *suggested_action = GDK_ACTION_ASK;
+ *possible_actions = actions;
+ }
+ else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
{
if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
- return (actions & GDK_ACTION_LINK) ? GDK_ACTION_LINK : 0;
+ {
+ if (actions & GDK_ACTION_LINK)
+ {
+ *suggested_action = GDK_ACTION_LINK;
+ *possible_actions = GDK_ACTION_LINK;
+ }
+ }
else if (state & GDK_CONTROL_MASK)
- return (actions & GDK_ACTION_COPY) ? GDK_ACTION_COPY : 0;
+ {
+ if (actions & GDK_ACTION_COPY)
+ {
+ *suggested_action = GDK_ACTION_COPY;
+ *possible_actions = GDK_ACTION_COPY;
+ }
+ return;
+ }
else
- return (actions & GDK_ACTION_MOVE) ? GDK_ACTION_MOVE : 0;
+ {
+ if (actions & GDK_ACTION_MOVE)
+ {
+ *suggested_action = GDK_ACTION_MOVE;
+ *possible_actions = GDK_ACTION_MOVE;
+ }
+ return;
+ }
}
else
{
- if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
- return GDK_ACTION_ASK;
+ *possible_actions = actions;
- if (actions & GDK_ACTION_COPY)
- return GDK_ACTION_COPY;
+ if ((state & (GDK_MOD1_MASK)) && (actions & GDK_ACTION_ASK))
+ *suggested_action = GDK_ACTION_ASK;
+ else if (actions & GDK_ACTION_COPY)
+ *suggested_action = GDK_ACTION_COPY;
else if (actions & GDK_ACTION_MOVE)
- return GDK_ACTION_MOVE;
+ *suggested_action = GDK_ACTION_MOVE;
else if (actions & GDK_ACTION_LINK)
- return GDK_ACTION_LINK;
+ *suggested_action = GDK_ACTION_LINK;
}
}
- return 0;
+ return;
}
static GdkCursor *
source_info->widget = widget;
gtk_widget_ref (source_info->widget);
source_info->context = gdk_drag_begin (source_info->ipc_widget->window,
- dest_info->context->targets,
- dest_info->context->actions);
+ dest_info->context->targets);
source_info->target_list = gtk_target_list_new (NULL, 0);
tmp_list = dest_info->context->targets;
dest_window, proto,
current_event->dnd.x_root,
current_event->dnd.y_root,
- context->suggested_action, time);
+ context->suggested_action,
+ context->actions, time);
selection = gdk_drag_get_selection (info->proxy_source->context);
if (selection &&
dest_window, proto,
current_event->dnd.x_root,
current_event->dnd.y_root,
- context->suggested_action, time);
+ context->suggested_action,
+ context->actions, time);
selection = gdk_drag_get_selection (info->proxy_source->context);
if (selection &&
GList *targets = NULL;
GList *tmp_list;
guint32 time = GDK_CURRENT_TIME;
+ GdkDragAction possible_actions, suggested_action;
g_return_val_if_fail (widget != NULL, NULL);
g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
info->widget = widget;
gtk_widget_ref (info->widget);
- info->context = gdk_drag_begin (info->ipc_widget->window,
- targets, actions);
+ info->context = gdk_drag_begin (info->ipc_widget->window, targets);
g_list_free (targets);
g_dataset_set_data (info->context, "gtk-info", info);
info->target_list = target_list;
gtk_target_list_ref (target_list);
+ info->possible_actions = actions;
+
info->cursor = NULL;
info->status = GTK_DRAG_STATUS_DRAG;
info->last_event = NULL;
info->selections = NULL;
info->icon_window = NULL;
+
+ gtk_drag_get_event_actions (event, info->button, actions,
+ &suggested_action, &possible_actions);
if (event)
- info->cursor = gtk_drag_get_cursor (
- gtk_drag_get_event_action (event, info->button, 0));
+ info->cursor = gtk_drag_get_cursor (suggested_action);
gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_begin",
info->context);
GtkDragSourceInfo *info = (GtkDragSourceInfo *)data;
GdkAtom selection;
GdkDragAction action;
+ GdkDragAction possible_actions;
GdkWindow *window = NULL;
GdkWindow *dest_window;
GdkDragProtocol protocol;
event->y_root = y_root;
}
- action = gtk_drag_get_event_action ((GdkEvent *)event,
- info->button,
- info->context->actions);
+ gtk_drag_get_event_actions ((GdkEvent *)event,
+ info->button,
+ info->possible_actions,
+ &action, &possible_actions);
info->cur_x = event->x_root - info->hot_x;
info->cur_y = event->y_root - info->hot_y;
&dest_window, &protocol);
if (gdk_drag_motion (info->context, dest_window, protocol,
- event->x_root, event->y_root, action,
+ event->x_root, event->y_root, action,
+ possible_actions,
event->time))
{
if (info->last_event)
gdk_pointer_ungrab (event->time);
+ gtk_grab_remove (widget);
+ gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
+ GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
+ info);
+ gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
+ GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
+ info);
+
if ((info->context->action != 0) && (info->context->dest_window != NULL))
{
gtk_drag_drop (info, event->time);
gtk_drag_drop_finished (info, FALSE, event->time);
}
- gtk_grab_remove (widget);
- gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
- GTK_SIGNAL_FUNC (gtk_drag_button_release_cb),
- info);
- gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
- GTK_SIGNAL_FUNC (gtk_drag_motion_cb),
- info);
-
/* Send on a release pair to the the original
* widget to convince it to release its grab. We need to
* call gtk_propagate_event() here, instead of